import { h, render } from 'vue'
import { Graph, Shape } from '@antv/x6'
import { Dnd } from '@antv/x6-plugin-dnd'
import {
  IDesignerOptions,
  EPluginKey,
  IPlugin,
  EDesignerEventKey,
  INode,
  EPopVisible
} from '@/types'
import { GRAPH, MANHATTAN_CONNECT, PLUGINS, ICON_ATOM_NODE, NODE_SOURCES } from './config'
import { NodeContainer } from './components'
import { keys, isFunction, isArray, uniqueId, replace } from 'lodash-es'
import { useContextMenu } from './hooks'

const { setContextMenu } = useContextMenu()

const clearPop = () => {
  setContextMenu(EPopVisible.HIDE)
}

// 初始化基础画布
const initGraph = (target: Designer, opts: IDesignerOptions) => {
  target.graph = new Graph({
    ...GRAPH,
    container: opts.container.graph,
    connecting: MANHATTAN_CONNECT
  })
}

// 初始化插件功能
const initPlugins = (target: Designer, opts: IDesignerOptions) => {
  const graph: Graph = target.graph as Graph
  const optsPlugin: IPlugin = opts.plugins || ({} as IPlugin)

  // 支持开关（boolean）来快速控制组件启用状态
  // 同时也支持用户自定义插件函数，自定义函数会覆盖默认配置
  keys(PLUGINS).forEach((key) => {
    const pluginKey = key as EPluginKey
    if (optsPlugin[pluginKey] !== false) {
      const pluginValue = isFunction(optsPlugin[pluginKey])
        ? optsPlugin[pluginKey](opts)
        : PLUGINS[pluginKey]
      graph.use(pluginValue(opts))
    }
  })
}
// 初始化可操作节点
const initNodeSource = (target: Designer, opts: IDesignerOptions) => {
  // 注册自定义节点类型
  Shape.HTML.register(ICON_ATOM_NODE)
  const nodeSources = NODE_SOURCES.map((group) => group.children).reduce((target, val) => {
    return target.concat(val)
  }, [])
  target.register(nodeSources)

  const nodeContainer = opts.container.node
  if (!nodeContainer) {
    console.error('nodeContainer is required')
    return
  }
  if (target.graph) {
    target.dnd = new Dnd({
      target: target.graph,
      scaled: false,
      dndContainer: nodeContainer
    })
  }

  const Component = h(NodeContainer, {
    groups: NODE_SOURCES,
    onMousedown: (e) => {
      const eventTarget = e.currentTarget
      const type = eventTarget.getAttribute('data-type')
      const node = nodeSources.find((n) => n.type === type)
      if (node) {
        const label = uniqueId(node.label)
        const instance = target.graph?.createNode({
          // shape: node.data.container ? type : ICON_NODE_NAME,
          width: node.width,
          height: node.height,
          shape: ICON_ATOM_NODE.shape,
          data: {
            ...node,
            label
          },
          label,
          ports: node.ports
        })
        if (instance) {
          target.dnd?.start(instance, e)
        }
      }
    }
  })

  render(Component, nodeContainer)
}

// 清除节点所有特殊状态
const clearAllNodeBuff = () => {
  const target = document.querySelector('g.x6-node.location')
  if (target) {
    const className = target.getAttribute('class') || ''
    target.setAttribute('class', replace(className, 'location', ''))
  }
}
// 初始化事件
const initEvents = (target: Designer, opts: IDesignerOptions) => {
  const globalWrapper: HTMLElement =
    document.querySelector('.full-screen') || document.createElement('div')
  globalWrapper.onclick = () => {
    clearAllNodeBuff()
  }

  const graph = target.graph as Graph
  const emits = opts.events || {}

  // 节点右键菜单事件
  graph.on(EDesignerEventKey.NODE_CONTEXTMENU, ({ e, node }) => {
    if (node) {
      const nodeData: INode = node.getData()
      if (nodeData.container) {
        console.log('容器')
      } else {
        console.log('非容器')
      }
      setContextMenu(EPopVisible.SHOW, {
        left: e.clientX + 'px',
        top: e.clientY + 'px'
      })
    }
  })

  // 节点双击事件
  graph.on(EDesignerEventKey.NODE_DBLCLICK, ({ node }) => {
    if (isFunction(emits[EDesignerEventKey.NODE_DBLCLICK])) {
      emits[EDesignerEventKey.NODE_DBLCLICK]?.({ node })
    }
  })

  // 节点resize时触发的事件
  graph.on(EDesignerEventKey.NODE_RESIZING, ({ node }) => {
    if (isFunction(emits[EDesignerEventKey.NODE_RESIZING])) {
      emits[EDesignerEventKey.NODE_DBLCLICK]?.({ node })
    }
  })

  // 画布新增节点事件
  graph.on(EDesignerEventKey.NODE_ADDED, ({ node }) => {
    if (isFunction(emits[EDesignerEventKey.NODE_ADDED])) {
      emits[EDesignerEventKey.NODE_ADDED]?.({ node })
    }
    if (isFunction(emits[EDesignerEventKey.NODE_CHANGE])) {
      emits[EDesignerEventKey.NODE_CHANGE]?.({ node })
    }
  })
  // 画布删除节点事件
  graph.on(EDesignerEventKey.NODE_REMOVED, ({ node }) => {
    if (isFunction(emits[EDesignerEventKey.NODE_REMOVED])) {
      emits[EDesignerEventKey.NODE_REMOVED]?.({ node })
    }
    if (isFunction(emits[EDesignerEventKey.NODE_CHANGE])) {
      emits[EDesignerEventKey.NODE_CHANGE]?.({ node })
    }
  })

  // 撤销/重做
  graph.bindKey(['meta+z', 'ctrl+z'], () => {
    if (graph.canUndo()) {
      graph.undo()
      if (isFunction(emits[EDesignerEventKey.GRAPH_CAN_UNDO])) {
        emits[EDesignerEventKey.GRAPH_CAN_UNDO]?.()
      }
    }
    return false
  })
  graph.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
    if (graph.canRedo()) {
      graph.redo()
      if (isFunction(emits[EDesignerEventKey.GRAPH_CAN_REDO])) {
        emits[EDesignerEventKey.GRAPH_CAN_UNDO]?.()
      }
    }
    return false
  })
  // 快捷键删除节点。主要用于框选删除的操作
  graph.bindKey('backspace', () => {
    const cells = graph.getSelectedCells()
    if (cells.length) {
      graph.removeCells(cells)
      // graph.removeCells(cells.filter((cell) => !cell.isNode()))

      // TODO: 删除节点
      if (isFunction(emits[EDesignerEventKey.GRAPH_BACKSPACE])) {
        emits[EDesignerEventKey.GRAPH_BACKSPACE]?.()
      }
    }
  })
}

export default class Designer {
  graph: Graph | null = null
  dnd: Dnd | null = null

  constructor(opts: IDesignerOptions) {
    this.init(opts)
  }

  init(opts: IDesignerOptions) {
    clearPop()
    initGraph(this, opts)
    initPlugins(this, opts)
    initNodeSource(this, opts)
    initEvents(this, opts)
  }

  register(nodes: Record<string, any>[]) {
    nodes = isArray(nodes) ? nodes : [nodes]

    nodes.forEach((n) => {
      Graph.registerNode(n.type, n, true)
    })
  }
}
